﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JBeamLibrary.Events;
using JBeamLibrary.VehicleParts.Elements;
using System.Collections.ObjectModel;
using JBeamLibrary.VehicleParts.Interfaces;

namespace JBeamLibrary.VehicleParts.Collections
{
    public class NodeCollection : KeyedCollection<string, Node>, IVehicleGroupCollection<Node>
    {
        #region Fields

        public event EventHandler<Node> NodeAdded;
        public event EventHandler NodeRemoved;
        public event ElementPropertyChangedEventHandler ElementPropertyChanged;

        #endregion

        #region CTORs

        /// <summary>Creates a new nodes collection</summary>
        public NodeCollection()
        {

        }

        /// <summary>Creates a new nodes collection</summary>
        /// <param name="nodes"></param>
        public NodeCollection(IEnumerable<Node> nodes)
        {
            AddRange(nodes);
        }

        #endregion

        #region Methods

        /// <summary>Adds a node</summary>
        /// <param name="node"></param>
        public new void Add(Node node)
        {
            base.Add(node);

            node.PropertyChanged += (s, e) =>
            {
                if (ElementPropertyChanged != null)
                    ElementPropertyChanged(s, e);
            };

            if (NodeAdded != null)
                NodeAdded(this, node);
        }

        /// <summary>Creates a node and adds it to the list</summary>
        /// <param name="id"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public void Add(string id, float x, float y, float z)
        {
            Add(new Node(id, x, y, z));
        }

        /// <summary>Adds a collection of nodes to the list</summary>
        /// <param name="nodes"></param>
        public void AddRange(IEnumerable<Node> nodes)
        {
            foreach (var node in nodes)
                Add(node);
        }

        /// <summary>Updates or adds the node with the given ID in the list</summary>
        /// <param name="id"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        public void UpdateAdd(string id, float x, float y, float z)
        {
            UpdateAdd(new Node(id, x, y, z));
        }

        /// <summary>Updates or adds the node with a matching ID in the list</summary>
        /// <param name="node"></param>
        public void UpdateAdd(Node node)
        {
            if (Contains(node.Id))
                Remove(node.Id);
            Add(node);
        }

        /// <summary>Updates or adds nodes of a given collection to the list</summary>
        /// <param name="nodes"></param>
        public void UpdateAddRange(IEnumerable<Node> nodes)
        {
            foreach (var node in nodes)
                UpdateAdd(node);
        }

        /// <summary>Removes a node</summary>
        /// <param name="node"></param>
        public new void Remove(Node node)
        {
            base.Remove(node);

            if (NodeRemoved != null)
                NodeRemoved(this, new EventArgs());
        }

        /// <summary>Removes the node at the specified index</summary>
        /// <param name="index"></param>
        public new void RemoveAt(int index)
        {
            base.RemoveAt(index);

            if (NodeRemoved != null)
                NodeRemoved(this, new EventArgs());
        }

        #endregion

        #region KeyedCollection

        protected override string GetKeyForItem(Node item)
        {
            return item.Id;
        }

        #endregion
    }
}
